home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
AMICUS
/
AMICUS14.ADF
/
Oings
/
Zoing
/
zoing.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-01-28
|
17KB
|
552 lines
char title [] = "Zoing! 1.0 (c) 1986 Alonzo Gariepy, Public Domain";
/* Simulates elastic collision of multiple balls in rectangular area. */
/* See the doc file accompanying this source code. */
/* */
/* 31 August 1986 Finished and released version 1.0, AMG */
/* */
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/sprite.h>
#define ONE_POINT_TWO 0 /* I'd rather do this dynamically */
#define MAXBALLS 8
#define BALLS balls_used /* defined on command line. */
#define FRACBITS 6 /* 0<x<7 fixed point integers. */
#define GRAVITY gravity /* defined by user. 2 is good. */
#define LEVITY levity /* defined by user. 1 is best. */
#define IS_HIRES 1 /* workbench always high res. */
#define IS_INTERLACE is_interlace /* variable due to interlace. */
#define STEPSPERFRAME 2 /* 0<x<? simulation resolution */
#define SHIFTX (FRACBITS-IS_HIRES)
#define SHIFTY shift_y /* variable due to interlace. */
#define MINX 0
#define MINY 0
#define MAXX (SIMX (304))
#define MAXY max_y /* variable due to interlace. */
/* defined in arguments */
long BALLS, IS_INTERLACE, SHIFTY, MAXY, GRAVITY, LEVITY;
#define BALL_SPRITE happyr
#define CURSOR_SPRITE charlie
#define HEAD_SPRITE harryr
#define WEIRD_SPRITE sunnyw
#define SIZEOF_SPRITE 36 /* total words including posctl and term */
#define CURSORDX 7 /* The offset from pointer to cursor sprite */
#define CURSORDY 7
#define D (SIMX (16))
#define CONX(x) ((x) << SHIFTX)
#define CONY(y) ((y) << SHIFTY)
#define SCREENX(x) ((x) >> SHIFTX)
#define SCREENY(y) ((y) >> SHIFTY)
#define SIMX(x) ((x) << FRACBITS)
#define SIMY(y) ((y) << FRACBITS)
struct NewWindow windef = {
0, 0, 84 + 8*sizeof(title) - 7, 20,
-1, -1,
CLOSEWINDOW,
WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG | WINDOWSIZING,
NULL, NULL,
title,
NULL, NULL, 84 + 8*sizeof("Zoing!") - 9, 0, 0, 0,
WBENCHSCREEN
};
extern UWORD charlie [SIZEOF_SPRITE];
extern UWORD amused [SIZEOF_SPRITE];
/* and you thought Castro was a yogurt for Unix programmers */
extern UWORD happyw [SIZEOF_SPRITE];
extern UWORD angryr [SIZEOF_SPRITE];
extern UWORD happyr [SIZEOF_SPRITE];
extern UWORD sunnyw [SIZEOF_SPRITE];
extern UWORD harryr [SIZEOF_SPRITE];
long framecount = 0;
long cursor = 0; /* boolean flag: window and cursor ball active */
long angry [MAXBALLS];
long alt_on [MAXBALLS];
struct SimpleSprite spr[MAXBALLS];
struct Window *win;
struct ViewPort *vp;
UWORD *sprbuf;
long x [MAXBALLS] = {0, SIMX(300),
SIMX(128),
SIMX(114), SIMX(114),
SIMX(100), SIMX(100), SIMX(100), };
long y [MAXBALLS] = {0, SIMY(10),
SIMY(92),
SIMY(84), SIMY(100),
SIMY(76), SIMY(92), SIMY(108), };
long vx [MAXBALLS] = {0, -180, 0, 0, 0, 0, 0, 0,};
long vy [MAXBALLS] = {0, 70, 0, 0, 0, 0, 0, 0,};
UWORD *sprites [MAXBALLS] = {charlie, sunnyw, harryr, happyr,
happyr, happyr, happyr, happyr, };
UWORD *sprites_alt [MAXBALLS] = {amused, sunnyw, harryr, angryr,
angryr, angryr, angryr, angryr, };
long GfxBase, IntuitionBase;
main (argc, argv)
long argc;
char *argv[];
{
int i;
openwindow ();
arguments (argc, argv);
copysprites ();
defineballs ();
for (;;)
{
trackcursor ();
doIDCMP ();
WaitTOF (vp);
for (i = 0; i < STEPSPERFRAME; ++i)
{
collisions ();
moveballs ();
}
showballs ();
}
}
arguments (argc, argv)
long argc;
char *argv [];
{
struct Screen screen;
char *name = (char *)0, usage [sizeof (title)];
long i, string = 0;
for (i = 0; i < sizeof (usage) - 1;)
if (name && (usage [i] = *name))
++name, ++i;
else
{
switch (string)
{
case 0: name = " Usage: ";
string = 1;
continue;
case 1: name = argv [0];
string = 2;
continue;
case 2: name = " balls(1..10) gravity(0..8) ";
string = 3;
continue;
case 3: break;
}
break;
}
usage [sizeof(usage) - 1] = (char)0;
BALLS = MAXBALLS;
GRAVITY = 0;
LEVITY = 0;
switch (argc)
{
case 4:
LEVITY = atoi (argv [3]);
if (LEVITY < 0 || LEVITY > 5)
seppuku (usage);
#ifdef VERS12
if (LEVITY && ONE_POINT_TWO)
ActivateWindow (win);
#endif
case 3:
GRAVITY = atoi (argv [2]);
if (GRAVITY < 0 || GRAVITY > 10)
seppuku (usage);
case 2:
BALLS = atoi (argv [1]) + 1;
if (*argv [1] == '?' || BALLS < 2 || BALLS > MAXBALLS)
seppuku (usage);
default:
break;
}
#ifdef VERS12
if (ONE_POINT_TWO)
{
if (!GetScreenData (&screen, sizeof(screen), WBENCHSCREEN, NULL))
seppuku ("Zoing! No workbench.");
IS_INTERLACE = (screen.Height > 300) ? 1 : 0;
SHIFTY = FRACBITS - IS_INTERLACE;
MAXY = CONY(screen.Height) - SIMY(16);
}
else
{
#endif
IS_INTERLACE = 0;
SHIFTY = FRACBITS;
MAXY = CONY(200) - SIMY(16);
#ifdef VERS12
}
#endif
}
trackcursor ()
{
static long oldx, oldy;
register long xx, yy;
if (win->Flags & WINDOWACTIVE)
{
x [0] = xx = CONX (win->WScreen->MouseX) - SIMX (CURSORDX);
y [0] = yy = CONY (win->WScreen->MouseY) - SIMX (CURSORDX);
if (cursor)
{
vx [0] = (xx - oldx) / STEPSPERFRAME;
vy [0] = (yy - oldy) / STEPSPERFRAME;
}
else
{
vx [0] = vy [0] = 0;
cursor = 1;
}
oldx = xx;
oldy = yy;
}
else
{
cursor = 0;
}
}
moveballs () /* move the balls and reflect from walls */
{
register int i;
x [0] += vx [0];
y [0] += vy [0];
for (i = 1; i < BALLS; i++)
{
x [i] += vx [i];
y [i] += vy [i];
for (;;) /* we might require several bounces */
{
if (x [i] <= MINX)
x [i] = MINX + MINX - x [i], vx [i] = -vx [i];
if (x [i] >= MAXX)
x [i] = MAXX + MAXX - x [i], vx [i] = -vx [i];
if (x [i] >= MINX)
break;
}
vy [i] += LEVITY;
for (;;)
{
if (y [i] <= MINY)
y [i] = MINY + MINY - y [i], vy [i] = -vy [i];
if (y [i] >= MAXY)
y [i] = MAXY + MAXY - y [i], vy [i] = -vy [i];
if (y [i] >= MINY)
break;
}
vy [i] += GRAVITY;
}
}
showballs ()
{
int i;
++framecount;
for (i = 1; i < BALLS; ++i)
{
if (alt_on [i] != angry [i])
{
ChangeSprite (vp, spr+i, angry[i] ? sprites_alt[i] : sprites[i]);
alt_on [i] = angry [i];
}
MoveSprite (vp, spr + i, SCREENX (x [i]), SCREENY (y [i]));
}
/* I used to make the cursor gloat here, but it was too distracting! */
}
openwindow ()
{
if (!(IntuitionBase = OpenLibrary ("intuition.library", 0)))
seppuku ("Zoing! Can't open Intuition.");
if (!(GfxBase = OpenLibrary ("graphics.library", 0)))
seppuku ("Zoing! Can't open graphics.");
if (!(win = (struct Window *) OpenWindow (&windef)))
seppuku ("Zoing! Can't open window.");
vp = (struct ViewPort *) ViewPortAddress (win);
}
defineballs ()
{
long i, j, color, red, green, blue;
for (i = 16; i <= 19; ++i)
{
color = GetRGB4 (vp->ColorMap, i);
red = color >> 8 & 0xF;
green = color >> 4 & 0xF;
blue = color & 0xF;
for (j = 4; j <= 12; j += 4)
SetRGB4 (vp, i + j, red, green, blue);
}
for (i = 1; i < BALLS; i++)
{
if (GetSprite (spr + i, -1) < 0)
seppuku ("Zoing! Sprite allocation failed. ");
spr [i].height = 16;
spr [i].x = SCREENX (x [i]);
spr [i].y = SCREENY (y [i]);
ChangeSprite (vp, spr + i, sprites [i]);
}
SetPointer (win, sprites [0], 16, 16, -CURSORDX, -CURSORDY);
SetWindowTitles (win, title, title);
}
free_resources ()
{
register int i;
for (i = 1; i < BALLS; i++)
if (spr [i].num)
FreeSprite ((long) spr [i].num);
if (sprbuf)
FreeMem (sprbuf, 2*2*SIZEOF_SPRITE * BALLS);
if (win)
CloseWindow (win);
if (GfxBase)
CloseLibrary (GfxBase);
if (IntuitionBase)
CloseLibrary (IntuitionBase);
}
doIDCMP ()
{
long msg;
if (msg = GetMsg (win -> UserPort))
{
ReplyMsg (msg);
free_resources ();
/* printf ("framecount = %ld\n", framecount); */
/* Sorry, not under Workbench. jjf 06-sep-86 */
exit (0);
}
}
seppuku (str)
char *str;
{
if (win)
{
SetWindowTitles (win, str, -1);
#ifdef VERS12
if (ONE_POINT_TWO)
ActivateWindow (win); /* don't die quietly */
#endif
WaitPort (win -> UserPort);
}
free_resources ();
exit (100);
}
copysprites ()
{
UWORD *cw; /* current position in buffer of sprite images */
UWORD *sprite; /* current position in sprite */
int i, j;
if (!(sprbuf = (UWORD *)
AllocMem (2 * 2*SIZEOF_SPRITE * BALLS, MEMF_CHIP)))
seppuku ("Zoing! Can't allocate sprite buffer. ");
cw = sprbuf; /* current position at top of buffer */
for (i = 0; i < BALLS; ++i)
{
sprite = sprites [i];
if (!sprite)
seppuku ("Zoing! Missing sprite definition. ");
sprites [i] = cw;
for (j = 0; j < SIZEOF_SPRITE; ++j)
*cw++ = *sprite++;
}
for (i = 0; i < BALLS; ++i)
{
sprite = sprites_alt [i];
if (!sprite)
seppuku ("Zoing! Missing sprite definition. ");
sprites_alt [i] = cw;
for (j = 0; j < SIZEOF_SPRITE; ++j)
*cw++ = *sprite++;
}
}
collisions ()
{
/* These are statics so we don't have to worry about stack size. */
long i, j;
long dx, dy, dh, halfdh, dvx, dvy, evx, evy;
for (i = cursor ? 0 : 1; i < BALLS; ++i)
for (j = i+1; j < BALLS; ++j)
{
dx = x [i] - x [j];
dy = y [i] - y [j];
if (dx > D || dx < -D || dy > D || dy < -D)
continue;
dh = dx*dx + dy*dy;
/* big chunk of fudge */
if (dh > D*D + (2 << 2*FRACBITS))
continue;
dvx = vx [i] - vx [j];
dvy = vy [i] - vy [j];
if (i == 0)
{
dvx = dvx*2 - dvx/2; /* first term: infinite mass */
dvy = dvy*2 - dvy/2; /* second term: bit inelastic */
}
evx = dx * dvx + dy * dvy; /* sign of relative speed */
if (evx >= 0) /* same velocity or position, or departing */
continue;
/* Since energy is proportional to the square of the velocity, simple */
/* rounding does not work (errors won't necessarily balance over time). */
/* We'll try to make sure that the middle round value always is rounded */
/* down by subtracting one from halfdh. */
halfdh = dh/2 - 1; /* if anything we lose energy */
evx = evx * dx;
if (evx > 0)
evx = (evx + halfdh) / dh;
else
evx = (evx - halfdh) / dh;
evy = (dx * dvy - dy * dvx) * dx;
if (evy > 0)
evy = dvy - (evy + halfdh) / dh;
else
evy = dvy - (evy - halfdh) / dh;
if (i) /* cursor doesn't change speed */
vx [i] -= evx, vy [i] -= evy;
vx [j] += evx;
vy [j] += evy;
/* some cute display stuff */
switch (i) /* personalities */
{
case 0:
if (j > 2)
angry [j] = 1; /* yuck! */
break;
case 1: case 2: /* the fun guys cheer */
angry [j] = 0; /* everybody up */
break;
default:
angry [i] |= angry [j]; /* infectious grief */
angry [j] |= angry [i];
break;
}
}
}
UWORD charlie [] = { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8,
0x0020, 0x3ffc, 0x00f0, 0x7ffe, 0x0ff8, 0x7ffe,
0x33cc, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xfe7f, 0xffff,
0x7ffe, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
};
UWORD amused [] = { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8,
0x0020, 0x3ffc, 0x00f0, 0x7ffe, 0x0ff8, 0x7ffe,
0x33cc, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xfe7f, 0xffff,
0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
};
UWORD happyw [] = { 0x0000, 0x0000, 0x0000, 0x07e0, 0x0020, 0x1ff8,
0x0070, 0x3ffc, 0x0ff8, 0x7ffe, 0x3ffc, 0x7ffe,
0xf3cf, 0xffff, 0xf3cf, 0xffff, 0xfeff, 0xffff,
0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xeff7, 0xffff,
0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
};
UWORD angryr [] = { 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8, 0x0000,
0x3ffc, 0x0000, 0x73ce, 0x0c30, 0x7dbe, 0x0240,
0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xfeff, 0x0100,
0xfdbf, 0x0240, 0xfe7f, 0x0180, 0xffff, 0x0000,
0x7ffe, 0x0000, 0x781e, 0x07e0, 0x3ffc, 0x0000,
0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
};
UWORD happyr [] = { 0x0000, 0x0000, 0x07e0, 0x0000, 0x1ff8, 0x0000,
0x3ffc, 0x0000, 0x7ffe, 0x0000, 0x7ffe, 0x0000,
0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xffff, 0x0000,
0xffff, 0x0000, 0xffff, 0x0000, 0xeff7, 0x1008,
0x77ee, 0x0810, 0x781e, 0x07e0, 0x3ffc, 0x0000,
0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
};
UWORD sunnyw [] = { 0x0000, 0x0000, 0x07e0, 0x07e0, 0x1ff8, 0x1ff8,
0x3ffc, 0x3ffc, 0x7ffe, 0x2184, 0x73ce, 0x4c32,
0xf3cf, 0xedb7, 0xffff, 0xe187, 0xfeff, 0xffff,
0xfdbf, 0xffff, 0xfe7f, 0xffff, 0xeff7, 0xffff,
0x77ee, 0x7ffe, 0x781e, 0x7ffe, 0x3ffc, 0x3ffc,
0x1ff8, 0x1ff8, 0x07e0, 0x07e0, 0x0000, 0x0000
};
UWORD harryr [] = { 0x0000, 0x0000, 0x07e0, 0x07e0, 0x1ff8, 0x1fd8,
0x3ffc, 0x3f8c, 0x7ffe, 0x7006, 0x7ffe, 0x4002,
0xf3cf, 0x0c30, 0xf3cf, 0x0c30, 0xfeff, 0x0100,
0xfdbf, 0x0240, 0xfe7f, 0x0180, 0xeff7, 0x1008,
0x77ee, 0x0810, 0x781e, 0x07e0, 0x3ffc, 0x0000,
0x1ff8, 0x0000, 0x07e0, 0x0000, 0x0000, 0x0000
};
/* This program was created with Vladimir Schwartz's editor, PTE, the */
/* best likely ever to be available for the Amiga. The sprite images */
/* were designed using Ray R. Larson's SpriteMaker. Funny how Charlie */
/* Chaplin and his look alike symbolize similar organizations... */